package tree.nodeType.numeric.functions;

import java.util.ArrayList;
import java.util.Random;

import model.Data;
import model.Stock;
import pools.PoolsManager;
import tree.Node;
import tree.TreeNodesManager;
import tree.nodeType.Numeric;
import tree.nodeType.numeric.NumericFunction;

/**
 * from wiki: recursive def  S1=Y1
 * 							 for t>1 St = a*Yt + (1-a)*St-1
 *
 * Yt is the value at a time period t.
 * a = 2/(N+1)[citation needed]. (N is the number of the stocks i have??)
 * @author Orit
 *
 */
public class ExponentialMovingAverage extends NumericFunction{

	
	public ExponentialMovingAverage(Node parent,int depth, int maxDepth, TreeNodesManager treeNodesManager) {
		super(1,parent,treeNodesManager,depth);
		initSons(depth,maxDepth,treeNodesManager);

	}
	public ExponentialMovingAverage() {}
	
	public double execute() {
		double St = 0;
		Stock stock=Data.get().getCurrentStock();
		final double a = 0.03; //not sure about that.(just if N is the number of the stocks i have??)
		if (!sons.isEmpty()){
			days=Math.abs((int) Math.round(((Numeric)sons.get(0)).execute()));
		}
		int startDay=stock.getClosePrice().size()-1;
		if (Data.get().getPhase()==Data.Phase.Train){
			startDay= stock.getClosePrice().size()-1 - Data.get().getDays();
		}
		int lastDay = (startDay - days);
		if (startDay > stock.getClosePrice().size()-1){
			startDay=stock.getClosePrice().size()-1;
		}
		if (lastDay < 0){
			lastDay=0;
		}
		if (startDay - lastDay > 400){
			lastDay = startDay - 400;
			if (lastDay<0){
				lastDay=0;
			}
		}
		if (lastDay>=0 && lastDay<=stock.getClosePrice().size()-1){
			St = stock.getClosePrice().get(lastDay);
		}
		
		for (int i=lastDay; i<startDay; i++){
			St = (a*(stock.getClosePrice().get(i))) + ((1-a)*(St));
		}
		return St;
	}


	@Override
	public void initSons(int depth, int maximumDepth, TreeNodesManager treeNodesManager) {
		if (depth+1<=maximumDepth && (random.nextDouble()<0.5 || depth<2)){
			sons.add(PoolsManager.get().getRandomNumericFuncNode(depth+1, maximumDepth, this,treeNodesManager));
		}
		
	}
	@Override
	public String toString() {	
		return "ExpMovingAVG function: days: "+days;
	}
	
	@Override
	protected Node clone(TreeNodesManager treeNodesManager,Node parent) {
		Node cloned= new ExponentialMovingAverage(this,treeNodesManager,parent);		
		return cloned;
	}
	
	@Override
	protected Node clone(Node parent) {
		Node cloned= new ExponentialMovingAverage(this,parent);		
		return cloned;
	}
	
	public ExponentialMovingAverage(ExponentialMovingAverage expAvg,Node parent){
		this.depth=expAvg.depth;
		this.days=expAvg.days;
		this.parent=parent;
		this.sonsNeeded=expAvg.sonsNeeded;
		this.random= new Random();
		this.sons= new ArrayList<Node>();
		for (Node son : expAvg.sons){
			this.sons.add(son.cloneSubTree(this));
		}
	}
	public ExponentialMovingAverage(ExponentialMovingAverage expAvg, TreeNodesManager treeNodesManager,Node parent){
		super(1,parent,treeNodesManager,expAvg.depth,expAvg.days);		
		for (Node son : expAvg.sons){
			this.sons.add(son.cloneSubTree(treeNodesManager,this));
		}
	}
}
